package com.babel.util.tools;

import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.stream.JsonReader;


/**
 * json util
 * 
 * @author tangzhi
 */
public class JSONUtil {

    /**
     * bean to json
     * 
     * @see file without date type
     */
    public static String beanToJson(Object obj, boolean serializeNullValue) {
        if (obj == null) {
            return null;
        }
        // Bean -> Json
        Gson gson = serializeNullValue ? new GsonBuilder().serializeNulls().create() : new Gson();
        String json = gson.toJson(obj);
        return json;
    }

    /**
     * bean to json 适用于毫秒
     * 
     * @see with date type
     */
    public static String beanWithDateToJson(Object obj, boolean serializeNullValue) {
        if (obj == null) {
            return null;
        }
        // date serializable
        GsonBuilder gsonBuilder = new GsonBuilder();
        Gson gson = serializeNullValue ? gsonBuilder.serializeNulls()
                .registerTypeAdapter(java.util.Date.class, new DateSerializerUtils()).setDateFormat(DateFormat.LONG)
                .create() : gsonBuilder.registerTypeAdapter(java.util.Date.class, new DateSerializerUtils())
                .setDateFormat(DateFormat.LONG).create();
        // Bean -> Json
        String json = gson.toJson(obj);
        return json;
    }

    /**
     * json to bean
     * 
     * @see file without date type
     */
    public static <T> T jsonToBean(String json, Class<T> clazz) {
        if (json == null || "".equals(json.trim())) {
            return null;
        }
        StringReader strReader = new StringReader(json);
        JsonReader jsonReader = new JsonReader(strReader);
        return jsonToBean(jsonReader, clazz);
    }

    private static <T> T jsonToBean(JsonReader json, Class<T> clazz) {
        if (json == null) {
            return null;
        }
        // Json -> Bean
        Gson gson = new Gson();
        T bean = gson.fromJson(json, clazz);
        return bean;
    }

    /**
     * json to bean 适用于毫秒
     * 
     * @see with date type
     */
    public static <T> T jsonWithDateToBean(String json, Class<T> clazz) {
        if (json == null || "".equals(json.trim())) {
            return null;
        }
        StringReader strReader = new StringReader(json);
        JsonReader jsonReader = new JsonReader(strReader);
        return jsonWithDateToBean(jsonReader, clazz);
    }

    private static <T> T jsonWithDateToBean(JsonReader json, Class<T> clazz) {
        if (json == null) {
            return null;
        }
        // date deserializable
        GsonBuilder gsonBuilder = new GsonBuilder();
        Gson gson = gsonBuilder.registerTypeAdapter(java.util.Date.class, new DateDeserializerUtils())
                .setDateFormat(DateFormat.LONG).create();
        // Json -> Bean
        T b = gson.fromJson(json, clazz);
        return b;
    }

    /**
     * list to json
     * 
     * @see without date type
     */
    public static <T> String listToJson(List<T> list, boolean serializeNullValue) {
        if (list == null) {
            return null;
        }
        // List -> Json
        Gson gson = serializeNullValue ? new GsonBuilder().serializeNulls().create() : new Gson();
        String json = gson.toJson(list);
        return json;
    }

    /**
     * list to json
     * 
     * @seee with date type
     */
    public static <T> String listWithDateToJson(List<T> list, boolean serializeNullValue) {
        if (list == null) {
            return null;
        }
        // date serializable
        GsonBuilder gsonBuilder = new GsonBuilder();
        Gson gson = serializeNullValue ? gsonBuilder.serializeNulls()
                .registerTypeAdapter(java.util.Date.class, new DateSerializerUtils()).setDateFormat(DateFormat.LONG)
                .create() : gsonBuilder.registerTypeAdapter(java.util.Date.class, new DateSerializerUtils())
                .setDateFormat(DateFormat.LONG).create();
        // List -> Json
        String json = gson.toJson(list);
        return json;
    }

    /**
     * json to list
     * 
     * @see without date type
     */
    public static <T> List<T> jsonToList(String json, Class<T> clazz) {
        if (json == null || "".equals(json.trim())) {
            return null;
        }
        // json -> List
        StringReader strReader = new StringReader(json);
        List<T> list = null;
        try {
            list = readForList(strReader, false, clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * json to list
     * 
     * @see with date type
     */
    public static <T> List<T> jsonWithDateToList(String json, Class<T> clazz) {
        if (json == null || "".equals(json.trim())) {
            return null;
        }

        // json -> List
        StringReader strReader = new StringReader(json);
        List<T> list = null;
        try {
            list = readForList(strReader, true, clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return list;
    }

    private static <T> List<T> readForList(Reader reader, boolean hasDate, Class<T> clazz) throws IOException {
        JsonReader jsonReader = new JsonReader(reader);
        List<T> objs = new ArrayList<T>();
        jsonReader.beginArray();
        while (jsonReader.hasNext()) {
            T obj = null;
            if (hasDate) {
                obj = jsonWithDateToBean(jsonReader, clazz);
            } else {
                obj = jsonToBean(jsonReader, clazz);
            }
            if (obj != null)
                objs.add(obj);
        }
        jsonReader.endArray();
        jsonReader.close();
        return objs;
    }

    /**
     * set to json
     * 
     * @see without date type
     */
    public static <T> String setToJson(Set<T> set, boolean serializeNullValue) {
        if (set == null) {
            return null;
        }
        // set -> Json
        Gson gson = serializeNullValue ? new GsonBuilder().serializeNulls().create() : new Gson();
        String json = gson.toJson(set);
        return json;
    }

    /**
     * set to json
     * 
     * @seee with date type
     */
    public static <T> String setWithDateToJson(Set<T> set, boolean serializeNullValue) {
        if (set == null) {
            return null;
        }
        // date serializable
        GsonBuilder gsonBuilder = new GsonBuilder();
        Gson gson = serializeNullValue ? gsonBuilder.serializeNulls()
                .registerTypeAdapter(java.util.Date.class, new DateSerializerUtils()).setDateFormat(DateFormat.LONG)
                .create() : gsonBuilder.registerTypeAdapter(java.util.Date.class, new DateSerializerUtils())
                .setDateFormat(DateFormat.LONG).create();
        // List -> Json
        String json = gson.toJson(set);
        return json;
    }

    /**
     * json to set
     * 
     * @see without date type
     */
    public static <T> Set<T> jsonToSet(String json, Class<T> clazz) {
        if (json == null || "".equals(json.trim())) {
            return null;
        }
        // json -> set
        StringReader strReader = new StringReader(json);
        Set<T> set = null;
        try {
            set = readForSet(strReader, false, clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return set;
    }

    /**
     * json to set
     * 
     * @see with date type
     */
    public static <T> Set<T> jsonWithDateToSet(String json, Class<T> clazz) {
        if (json == null || "".equals(json.trim())) {
            return null;
        }

        // json -> set
        StringReader strReader = new StringReader(json);
        Set<T> set = null;
        try {
            set = readForSet(strReader, true, clazz);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return set;
    }

    private static <T> Set<T> readForSet(Reader reader, boolean hasDate, Class<T> clazz) throws IOException {
        JsonReader jsonReader = new JsonReader(reader);
        Set<T> objs = new HashSet<T>();
        jsonReader.beginArray();
        while (jsonReader.hasNext()) {
            T obj = null;
            if (hasDate) {
                obj = jsonWithDateToBean(jsonReader, clazz);
            } else {
                obj = jsonToBean(jsonReader, clazz);
            }
            if (obj != null)
                objs.add(obj);
        }
        jsonReader.endArray();
        jsonReader.close();
        return objs;
    }

    /**
     * map to json
     * 
     * @see whithout date type
     */
    public static <T> String mapToJson(Map<String, T> map, boolean serializeNullValue) {
        if (map == null) {
            return null;
        }
        // Map -> Json
        Gson gson = serializeNullValue ? new GsonBuilder().serializeNulls().create() : new Gson();
        String json = gson.toJson(map);
        return json;
    }

    /**
     * map to json
     * 
     * @see with date type
     */
    public static <T> String mapWithDateToJson(Map<String, T> map, boolean serializeNullValue) {
        if (map == null) {
            return null;
        }
        // date serializable
        GsonBuilder gsonBuilder = new GsonBuilder();
        Gson gson = serializeNullValue ? gsonBuilder.serializeNulls()
                .registerTypeAdapter(java.util.Date.class, new DateSerializerUtils()).setDateFormat(DateFormat.LONG)
                .create() : gsonBuilder.registerTypeAdapter(java.util.Date.class, new DateSerializerUtils())
                .setDateFormat(DateFormat.LONG).create();
        // map -> json
        String json = gson.toJson(map);
        return json;
    }

    /**
     * 日期解序列实用工具类
     */
    static class DateSerializerUtils implements JsonSerializer<java.util.Date> {
        public JsonElement serialize(Date date, Type type, JsonSerializationContext content) {
            return new JsonPrimitive(date.getTime());
        }

    }

    /**
     * 日期序列化实用工具类
     */
    static class DateDeserializerUtils implements JsonDeserializer<java.util.Date> {
        public java.util.Date deserialize(JsonElement json, Type type, JsonDeserializationContext context)
                throws JsonParseException {
            return new java.util.Date(json.getAsJsonPrimitive().getAsLong());
        }
    }
    public static Map<String, Object> parseJSON2Map(String jsonStr){
        HashMap<String, Object> data = new HashMap<String, Object>();
        // 将json字符串转换成jsonObject
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        Iterator<?> it = jsonObject.keySet().iterator();
        // 遍历jsonObject数据，添加到Map对象
        while (it.hasNext())
        {
            String key = String.valueOf(it.next());
            Object value = jsonObject.get(key);
            data.put(key, value);
        }
        return data;
    }
    public static void main(String[] args) {
        List<String> testDate=new ArrayList<String>();
        testDate.add("1111");
        testDate.add("2222");
        testDate.add("33333");
        Map<String,Object> map=new HashMap<String, Object>();
        map.put("testMap",testDate);
      String jsonData=  JSONUtil.mapToJson(map,true);
        System.out.println(jsonData);
        Map<String,Object> resultData= JSONUtil.parseJSON2Map(jsonData);
        System.out.println(resultData.toString());
    }
    
    public static org.json.JSONObject getJSONObject(){
    	return new org.json.JSONObject();
    }
}
